package com.haohan.jingyuan.user.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.haohan.jingyuan.common.constants.CacheConstants;
import com.haohan.jingyuan.common.enums.ErrorEnum;
import com.haohan.jingyuan.common.enums.UserStatusEnum;
import com.haohan.jingyuan.common.exception.BusinessException;
import com.haohan.jingyuan.common.util.EntityUtil;
import com.haohan.jingyuan.gateway.holder.UserContextHolder;
import com.haohan.jingyuan.user.dao.UserInfoMapper;
import com.haohan.jingyuan.user.dto.req.CreateUserRequest;
import com.haohan.jingyuan.user.dto.req.DeleteUserRequest;
import com.haohan.jingyuan.user.dto.req.FreezeUserRequest;
import com.haohan.jingyuan.user.dto.req.LoginRequest;
import com.haohan.jingyuan.user.dto.req.QueryUserListRequest;
import com.haohan.jingyuan.user.dto.req.ResetPasswordRequest;
import com.haohan.jingyuan.user.dto.req.UpdatePasswordRequest;
import com.haohan.jingyuan.user.dto.req.UpdateUserRequest;
import com.haohan.jingyuan.user.dto.resp.LoginResp;
import com.haohan.jingyuan.user.dto.resp.UserInfoResp;
import com.haohan.jingyuan.user.dto.resp.UserListResp;
import com.haohan.jingyuan.user.entity.UserInfo;
import com.haohan.jingyuan.user.helper.UserInfoRespHelper;
import com.haohan.jingyuan.util.CacheUtil;
import com.haohan.jingyuan.util.UuidUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 用户服务实现类
 *
 * @ClassName UserService
 * @Description 用户相关业务逻辑实现
 * @Author hexijun
 * @Time 2025/01/18 22:20
 * @Version 1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserService {

    private final UserInfoMapper userInfoMapper;
    private final CacheUtil cacheUtil;

    /**
     * 创建用户
     *
     * @param request 创建用户请求
     * @return 用户信息
     */
    public UserInfoResp createUser(CreateUserRequest request) {
        log.info("UserService.createUser BEGIN ==> userName: {}", request.getUserName());

        // 检查用户名是否已存在
        UserInfo existingUser = userInfoMapper.findByUserName(request.getUserName());
        if (existingUser != null) {
            throw new BusinessException(ErrorEnum.USER_ALREADY_EXISTS);
        }

        // 创建用户信息
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(UuidUtil.generateId("UID_", 8));
        userInfo.setUserName(request.getUserName());
        String pasword = UuidUtil.generateId(4);
        userInfo.setPassWord(DigestUtils.md5Hex(pasword));
        userInfo.setStatus(UserStatusEnum.NORMAL.getCode());
        EntityUtil.setCreateAndModifyInfo(userInfo, UserContextHolder.getCurrentUserName());

        // 保存到数据库
        int result = userInfoMapper.insert(userInfo);
        if (result <= 0) {
            throw new BusinessException(ErrorEnum.DATABASE_ERROR);
        }

        UserInfoResp userInfoResp = UserInfoRespHelper.convert2UserInfoResp(userInfo);
        userInfoResp.setPassWord(pasword);
        log.info("UserService.createUser END ==> {}", userInfoResp);
        return userInfoResp;
    }

    /**
     * 重置用户密码
     *
     * @param request 重置密码请求
     * @return 用户信息
     */
    public UserInfoResp resetPassword(ResetPasswordRequest request) {
        // 查询用户是否存在
        UserInfo userInfo = userInfoMapper.selectById(request.getId());
        if (userInfo == null) {
            throw new BusinessException(ErrorEnum.USER_NOT_FOUND);
        }

        // 生成新密码
        String newPassword = UuidUtil.generateId(4);
        userInfo.setPassWord(DigestUtils.md5Hex(newPassword));

        // 设置修改信息
        EntityUtil.setModifyInfo(userInfo, UserContextHolder.getCurrentUserName());

        // 更新数据库
        int result = userInfoMapper.updateById(userInfo);
        if (result <= 0) {
            throw new BusinessException(ErrorEnum.DATABASE_ERROR);
        }

        UserInfoResp userInfoResp = UserInfoRespHelper.convert2UserInfoResp(userInfo);
        userInfoResp.setPassWord(newPassword);
        return userInfoResp;
    }

    /**
     * 冻结用户
     *
     * @param request 冻结用户请求
     * @return 用户信息
     */
    public UserInfoResp freezeUser(FreezeUserRequest request) {
        // 查询用户是否存在
        UserInfo userInfo = userInfoMapper.selectById(request.getId());
        if (userInfo == null) {
            throw new BusinessException(ErrorEnum.USER_NOT_FOUND);
        }

        // 更新用户状态为冻结
        userInfo.setStatus(UserStatusEnum.FROZEN.getCode());

        // 设置修改信息
        EntityUtil.setModifyInfo(userInfo, UserContextHolder.getCurrentUserName());

        // 更新数据库
        int result = userInfoMapper.updateById(userInfo);
        if (result <= 0) {
            throw new BusinessException(ErrorEnum.DATABASE_ERROR);
        }

        UserInfoResp userInfoResp = UserInfoRespHelper.convert2UserInfoResp(userInfo);
        return userInfoResp;
    }

    /**
     * 查询用户列表
     *
     * @param request 查询用户列表请求
     * @return 用户列表
     */
    public UserListResp queryUserList(QueryUserListRequest request) {
        // 创建分页对象
        Page<UserInfo> page = new Page<>(request.getPageNum(), request.getPageSize());

        // 分页查询
        IPage<UserInfo> userPage = userInfoMapper.selectUserListPage(page,
                request.getUserName(), request.getStatus(), request.getGmtCreatedStart(), request.getGmtCreatedEnd());

        // 转换为响应对象
        List<UserInfoResp> userList = new ArrayList<>();
        for (UserInfo record : userPage.getRecords()) {
            userList.add(UserInfoRespHelper.convert2UserInfoResp(record));
        }

        UserListResp response = new UserListResp();
        response.setUserList(userList);
        response.setTotal(userPage.getTotal());
        response.setPageNum(request.getPageNum());
        response.setPageSize(request.getPageSize());
        response.setTotalPages((int) userPage.getPages());
        return response;
    }

    /**
     * 登录
     *
     * @param loginRequest
     * @return 认证成功时返回JWT token，认证失败时返回null
     */
    public LoginResp login(LoginRequest loginRequest) {
        String username = loginRequest.getUsername();
        String password = loginRequest.getPassword();

        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            log.warn("用户登录用户名和密码不可为空");
            return null;
        }

        // 登录次数校验：每日5次
        String cacheKey = CacheConstants.CACHE_LOGIN_TIMES_ + username;
        Integer loginTimes = cacheUtil.get(cacheKey, Integer.class);
        if (loginTimes == null) {
            loginTimes = 0;
        } else if (loginTimes > 10) {
            throw new BusinessException(ErrorEnum.LOGIN_TIMES);
        }

        // 对入参密码进行 MD5 摘要后再比对
        String md5Password = DigestUtils.md5Hex(password);
        UserInfo userInfo = userInfoMapper.findByUsernameAndPassword(username, md5Password);

        if (userInfo == null) {
            cacheUtil.put(cacheKey, loginTimes++);
            return null;
        }

        if (!UserStatusEnum.NORMAL.getCode().equals(userInfo.getStatus())) {
            throw new BusinessException(ErrorEnum.USER_STATUS_ERROR);
        }

        // 登录成功，生成token并缓存
        LoginResp loginResp = new LoginResp();
        loginResp.setAuthToken(generateAndCacheToken(userInfo));
        loginResp.setUserId(userInfo.getUserId());
        loginResp.setUserName(userInfo.getUserName());
        // 登录成功，token缓存用户信息
        cacheUtil.put(loginResp.getAuthToken(), userInfo);

        return loginResp;
    }

    /**
     * 用户登出
     *
     * @return 登出是否成功
     */
    public boolean logout() {

        String userId = UserContextHolder.getCurrentUserId();
        String authToken = UserContextHolder.getCurrentToken();

        if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(authToken)) {
            log.warn("非法操作：登出异常，用户id或authToken为空,userId={},authToken={}", userId, authToken);
            throw new BusinessException(ErrorEnum.LOGOUT_ERROR);
        }

        try {
            UserInfo userInfo = cacheUtil.get(authToken, UserInfo.class);
            if (userInfo != null) {
                if (!userInfo.getUserId().equals(userId)) {
                    log.warn("非法操作：登录时用户id与authToken不符合,userId={},authToken={}", userId, authToken);
                    throw new BusinessException(ErrorEnum.LOGOUT_ERROR);
                }
                cacheUtil.remove(authToken);
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            log.error("用户登出失败，userId={},authToken={}", userId, authToken, e.getMessage(), e);
            return false;
        }
    }

    /**
     * 修改用户密码
     *
     * @param updatePasswordRequest
     * @return 更新是否成功
     */
    public boolean updatePassword(UpdatePasswordRequest updatePasswordRequest) {

        String userId = UserContextHolder.getCurrentUserId();
        String modifier = UserContextHolder.getCurrentUserId();
        String newPassword = updatePasswordRequest.getNewPassword();

        if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(newPassword) || StringUtils.isEmpty(modifier)) {
            log.warn("修改密码失败：用户ID、新密码或修改人不能为空，userId={}, modifier={}", userId, modifier);
            return false;
        }

        try {
            // 对新密码进行MD5加密
            String md5Password = DigestUtils.md5Hex(newPassword);

            // 更新密码
            int updateCount = userInfoMapper.updatePasswordByUserId(userId, md5Password, modifier);

            if (updateCount > 0) {
                log.info("修改密码成功，userId={}, modifier={}", userId, modifier);
                return true;
            } else {
                log.warn("修改密码失败：用户不存在或更新失败，userId={}, modifier={}", userId, modifier);
                return false;
            }
        } catch (Exception e) {
            log.error("修改密码异常，userId={}, modifier={}", userId, modifier, e);
            return false;
        }
    }


    /**
     * 编辑用户信息
     *
     * @param request 编辑用户请求
     * @return 用户信息
     */
    public UserInfoResp updateUser(UpdateUserRequest request) {
        // 查询用户是否存在
        Long id = Long.parseLong(request.getId());
        UserInfo userInfo = userInfoMapper.selectById(id);
        if (userInfo == null) {
            throw new BusinessException(ErrorEnum.USER_NOT_FOUND);
        }

        // 如果更新用户名，检查用户名是否与其他用户重复
        if (request.getUserName() != null && !request.getUserName().trim().isEmpty()) {
            UserInfo existingUser = userInfoMapper.findByUserName(request.getUserName());
            if (existingUser != null && !existingUser.getId().equals(id)) {
                throw new BusinessException(ErrorEnum.USER_ALREADY_EXISTS);
            }
            userInfo.setUserName(request.getUserName());
        }

        // 更新用户状态
        if (request.getStatus() != null && !request.getStatus().trim().isEmpty()) {
            userInfo.setStatus(request.getStatus());
        }

        // 设置修改信息
        EntityUtil.setModifyInfo(userInfo, UserContextHolder.getCurrentUserName());

        // 更新数据库
        int result = userInfoMapper.updateById(userInfo);
        if (result <= 0) {
            throw new BusinessException(ErrorEnum.DATABASE_ERROR);
        }

        UserInfoResp userInfoResp = UserInfoRespHelper.convert2UserInfoResp(userInfo);
        return userInfoResp;
    }

    /**
     * 删除用户信息
     *
     * @param request 删除用户请求
     * @return 删除结果
     */
    public boolean deleteUser(DeleteUserRequest request) {
        // 查询用户是否存在
        Long id = Long.parseLong(request.getId());
        UserInfo userInfo = userInfoMapper.selectById(id);
        if (userInfo == null) {
            throw new BusinessException(ErrorEnum.USER_NOT_FOUND);
        }

        // 逻辑删除
        EntityUtil.logicalDelete(userInfo, UserContextHolder.getCurrentUserName());

        // 更新数据库
        int result = userInfoMapper.updateById(userInfo);
        if (result <= 0) {
            throw new BusinessException(ErrorEnum.DATABASE_ERROR);
        }

        return true;
    }

    /**
     * 生成并缓存用户登录token
     *
     * @param userInfo 用户信息
     * @return 生成的token（格式：userId uuid）
     */
    private String generateAndCacheToken(UserInfo userInfo) {
        String uuid = UUID.randomUUID().toString().replace("-", "");
        return userInfo.getUserId() + " " + uuid;
    }
}
